Terraform으로 EC2를 구축해보기

Terraform으로 EC2를 구축해보기

Clock Icon2024.12.20

안녕하세요. 클래스메소드의 서은우입니다.

Terraform 을 사용해 AWS 리소스를 구축해보았습니다.

시작하기에 앞서

생성할 리소스

Terraform 으로 Public Subnet에 위치한 EC2 인스턴스를 생성합니다.

파일 구조

작성한 Terraform 파일의 구조는 다음과 같습니다.

  • main.tf
    • Provider 를 정의
  • aws.tf
    • 생성할 AWS 리소스를 정의
  • variables.tf
    • aws.tf 파일에서 사용할 변수와 값을 정의

Terraform 사용을 위한 IAM Role 설정

Terraform을 이용해 AWS 리소스를 생성하기 위해서는 적절한 권한이 부여되어 있는 IAM 유저 혹은 역할이 필요합니다.

Terraform 배포를 위해 권한이 부여되어 있는 IAM User 를 사용하는 것도 가능하지만,
필요한 권한을 임시로 얻을 수 있는 AssumeRole을 사용하도록 하겠습니다.

Assume Role 에 대해서는 Terraform 의 aws_caller_identity 를 main.tf 파일에 작성하여 구현하도록 하겠습니다.

Terraform 작성

main.tf

# main.tf

terraform {
    required_providers {
        aws = {
            source = "hashicorp/aws"
            version = "< 5.71.0"
        }
    }
}

provider "aws" {
    region = "ap-northeast-1"

    # Assume Role 대상 role의 ARN
    assume_role {
      role_arn = "arn:aws:iam::<AWS_ACCOUNT>:role/terraform_role"
    }
}

data "aws_caller_identity" "current" {}

provider 블록에서는 리소스를 생성할 리전과 assume_role 을 하기 위한 대상 role의 ARN 을 지정해줍니다.

aws_caller_identity 는 지정된 계정의 ID를 참조하는 데이터 소스로 파라메터에 current를 지정하여 현재 계정 정보를 참조할 수 있습니다.

초기화

main.tf 파일을 작성하고 프로바이더에 대한 정의가 완료되었으면 terraform init 명령어로 테라폼을 초기화합니다.
초기화 작업은 한 번이 아니라, 이후에 프로바이더에 변경이 있을 경우에도 실행해주어야합니다.

terraform init
...
Terraform has been successfully initialized!

variables.tf

variables.tf 파일에서는 aws.tf 파일에서 사용할 변수들을 선언합니다.
이곳에서 선언한 변수들은 aws.tf 파일에서 var.변수명의 형식으로 사용하는 것이 가능합니다.

variable "vpc_cidr" {
 description = "VPC CIDR block"
 type = string
 default = "192.168.0.0/16"
}

variable "public_subnet_cidr" {
  description = "Public subnet CIDR block"
  type = string
  default = "192.168.0.0/24"
}

variable "az_1a" {
  description = "Availability zone ap-northeast-1a"
  type = string
  default = "ap-northeast-1a"
}

variable "ec2_type" {
  description = "EC2 Insatance Type"
  type = string
  default = "t3.micro"
}

variable "ami" {
  description = "EC2 AMI"
  type = string
  default = "ami-08ce76bae392de7dc"
}

aws.tf

해당 파일에는 생성한 리소스들을 정의합니다.

# IAM Role(EC2 인스턴스 프로파일용)
resource "aws_iam_role" "ssm_role" {
  name               = "ec2_ssm_role"
  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "ssm_attach" {
  role       = aws_iam_role.ssm_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

# VPC
resource "aws_vpc" "vpc" {
  # var.xxx 의 경우, variables.tf 에서 선언한 변수를 참조
  cidr_block = var.vpc_cidr

  tags = {
    Name = "test"
  }
}

# 퍼블릭 서브넷
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.vpc.id
  cidr_block              = var.public_subnet_cidr
  availability_zone       = var.az_1a
  map_public_ip_on_launch = true

  tags = {
    Name = "test-subnet-public"
  }
}

resource "aws_network_interface" "test" {
  subnet_id = aws_subnet.public.id
}

# 인터넷 게이트웨이
resource "aws_internet_gateway" "igw" {
  vpc_id = aws_vpc.vpc.id

  tags = {
    Name = "test-igw"
  }
}

# Route table
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.vpc.id

  route {
    cidr_block = var.vpc_cidr
    gateway_id = "local"
  }
}

resource "aws_route" "public" {
  route_table_id         = aws_route_table.public.id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.igw.id
}

resource "aws_route_table_association" "public" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

# EC2
resource "aws_instance" "ad_server" {
  instance_type = var.ec2_type
  ami           = var.ami
  subnet_id     = aws_subnet.public.id
  associate_public_ip_address = true # 퍼블릭 IP 할당
  vpc_security_group_ids = [aws_security_group.allow_ssh.id]

  iam_instance_profile = aws_iam_instance_profile.ssm_profile.name
  key_name = "tokyo-region-key"

  tags = {
    Name = "test_ec2"
    Profile = "SSM_Profile"
  }
}

resource "aws_iam_instance_profile" "ssm_profile" {
  name = "ssm_ec2_profile"
  role = aws_iam_role.ssm_role.name
}

# 보안그룹
resource "aws_security_group" "allow_ssh" {
  name        = "ssh_sg"
  description = "Allow ssh"
  vpc_id      = aws_vpc.vpc.id

  tags = {
    Name = "ssg_sg"
  }
}

# 보안그룹 인바운드 룰
resource "aws_vpc_security_group_ingress_rule" "allow_ssh" {
  security_group_id = aws_security_group.allow_ssh.id

  cidr_ipv4 = "xxx.xxx.xxx.xxx/xx"
  to_port = 22
  from_port = 22
  ip_protocol = "tcp"
}

Terraform 배포

작성한 Terraform 코드는 terraform plan 명령어로 실제로 리소스가 어떻게 생성될 것인지 확인하거나 terraform apply 명령어로 리소스를 실제로 생성하기 위해 배포할 수 있습니다.

# 리소스가 어떻게 생성될지 확인
terraform plan

# 문제가 없다면 실제로 리소스를 생성
terraform apply

끝으로

Terraform 을 사용하여 EC2 서버를 생성해 보았습니다.
본 블로그에서는 단순히 한 대의 EC2를 생성해보았지만 앞으로 더욱 복잡한 환경과 리소스도 테라폼으로 구축할 수 있도록 공부해보고 싶습니다.

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.